home *** CD-ROM | disk | FTP | other *** search
/ ...taking it to the Macs! / ...taking it to the Macs!.iso / Extras / ActiveX Mac SDK / ActiveX SDK / Container Common / binhex.c < prev    next >
Text File  |  1997-01-03  |  36KB  |  1,393 lines

  1. #ifdef _MSC_VER
  2. #include <macos\msvcmac.h>
  3. #include <string.h>
  4. #endif
  5. //----------------------------------------------
  6. // Global includes
  7. //----------------------------------------------
  8.  
  9. #include <Types.h>
  10. #include <Files.h>
  11.  
  12. #include "BinHex.h"
  13.  
  14. //----------------------------------------------
  15. // Local includes
  16. //----------------------------------------------
  17.  
  18. #include <Resources.h>
  19. #include <Finder.h>
  20. #include <Errors.h>
  21. #include <TextUtils.h>
  22. #include <PLStringFuncs.h>
  23.  
  24. //----------------------------------------------
  25. // InputBuffer structure
  26. //----------------------------------------------
  27.  
  28. #define cIgnoreChecksums 0
  29.  
  30. #define cBuffer_Size 16384
  31.  
  32. typedef struct {
  33.     UInt32    FileOffset;
  34.     
  35.     UInt8    Buffer[cBuffer_Size];
  36.     UInt32    BytesInBuffer;
  37.     
  38.     UInt32    BufferOffset;
  39.     UInt32    BytesAvailable;
  40.     } tInputBuffer;
  41.  
  42. typedef struct {
  43.     UInt32            FileOffset;
  44.     
  45.     UInt8            Buffer[cBuffer_Size];
  46.     UInt32            BytesInBuffer;
  47.     
  48.     UInt32            BufferOffset;
  49.     UInt32            BytesAvailable;
  50.     
  51.     Boolean            TerminatorFound;
  52.     
  53.     UInt8            ConversionTable[256];
  54.     
  55.     int                HoldingPhase;
  56.     UInt8            HoldingByte;
  57.     UInt8            PreviousByte;
  58.     Boolean            RepeatFlagFound;
  59.     } tBinHexBuffer;
  60.  
  61. #pragma options align=mac68k
  62.  
  63. typedef struct {
  64.     Str63    FileName;
  65.     
  66.     OSType    FileType;
  67.     OSType    FileCreator;
  68.     UInt16    FinderFlags;
  69.     UInt32    DataLength;
  70.     UInt32    ResourceLength;
  71.     } tBinHexFileHeader;
  72.  
  73. #pragma options align=reset
  74.     
  75. //----------------------------------------------
  76. // tBinHexParser
  77. //----------------------------------------------
  78.  
  79. typedef enum {
  80.     cValidating_ParserState = 0,
  81.     cHeaderNameLength_ParserState,
  82.     cHeaderName_ParserState,
  83.     cHeaderNamePad_ParserState,
  84.     cHeader_ParserState,
  85.     cHeaderChecksum_ParserState,
  86.     cDataFork_ParserState,
  87.     cDataForkChecksum_ParserState,
  88.     cResourceFork_ParserState,
  89.     cResourceForkChecksum_ParserState,
  90.     cPassThrough_ParserState,
  91.     cDiscard_ParserState
  92.     } tBinHexParserState;
  93.  
  94. struct tBinHexParser
  95. {
  96.     tBinHexClientData *            fClientData;
  97.     tBinHexParserCallbacks *    fCallbacks;
  98.     
  99.     tInputBuffer *                fInputBuffer;
  100.     tBinHexBuffer *                fBinHexBuffer;
  101.     
  102.     tBinHexParserState            fParserState;
  103.     
  104.     tBinHexFileHeader            fHeader;
  105.     UInt16                        fCalculatedChecksum;
  106.     UInt16                        fActualChecksum;
  107.     
  108.     long                        fByteCount;    // Meaning is state-dependent:
  109.                                             //         cValidating_ParserState: # bytes of header accumulated
  110.                                             //        cDataFork_ParserState: # bytes of data fork remaining
  111.                                             //        cDataGap_ParserState: # bytes of data gap remaining
  112.                                             //        cResourceFork_ParserState: # bytes of resource fork remaining
  113.                                             //        cResourceGap_ParserState: # bytes of resource gap remaining
  114.                                             //        cPassThrough_ParserState: no meaning
  115.                                             //        cDiscard_ParserState: no meaning
  116. };
  117.  
  118. //----------------------------------------------
  119. // Local prototypes
  120. //----------------------------------------------
  121.  
  122. static OSErr    SkipReturn(tInputBuffer *pBuffer);
  123. static OSErr    ReadFileToReturn(tInputBuffer *pBuffer, Boolean pKeepSpaces, void *pData, long pMaxLength, long *rActualLength);
  124. static OSErr    ReadOneCharacter(tInputBuffer *pBuffer, char *rCharacter);
  125. static OSErr    FindBinHexHeader(tInputBuffer *pBuffer);
  126.  
  127. static Boolean    BinHexBuffer_New(tBinHexBuffer **rBuffer);
  128. static void        BinHexBuffer_Dispose(tBinHexBuffer *pBuffer);
  129. static OSErr    BinHexBuffer_LoadFromFile(tBinHexBuffer *pBuffer, tInputBuffer *pInputBuffer, short pFileRef);
  130. static Boolean    BinHexBuffer_Stuff(tBinHexBuffer *pBuffer, UInt8 *pData, UInt32 pNumberOfBytes, UInt32 *rBytesStuffed);
  131. static OSErr    BinHexBuffer_ReadByte(tBinHexBuffer *pBuffer, UInt8 *rByte, UInt16 *rChecksum);
  132. static OSErr    BinHexBuffer_ReadBytes(tBinHexBuffer *pBuffer, UInt8 *pReadBuffer, UInt32 pNumberOfBytes, UInt16 *rChecksum);
  133.  
  134. static void        AddByteToBinHexChecksum(UInt8 pValue, UInt16 *rChecksum);
  135. static void        AddBytesToBinHexChecksum(UInt8 *pValues, UInt32 pNumberOfBytes, UInt16 *rChecksum);
  136.  
  137. static OSErr    GetBinHexFileHeader(tBinHexBuffer *pBuffer, Boolean *rHeaderIsValid, tBinHexFileHeader *rHeader);
  138. static Boolean    CopyBinHexToFile(tBinHexBuffer *pBuffer, tInputBuffer *pInputBuffer, short pSourceFileRef, short pDestFileRef, UInt32 pNumberOfBytes, UInt16 *rChecksum);
  139.  
  140. // InputBuffer
  141.  
  142. static Boolean    InputBuffer_New(tInputBuffer **rBuffer);
  143. static void        InputBuffer_Dispose(tInputBuffer *pBuffer);
  144.  
  145. static OSErr    InputBuffer_LoadFromFile(tInputBuffer *pBuffer, short pFileRef);
  146. static long        InputBuffer_Stuff(tInputBuffer *pInputBuffer, void *pData, long pNumberOfBytes);
  147. static void        InputBuffer_DeleteOldData(tInputBuffer *pInputBuffer);
  148. static void        InputBuffer_GetPointer(tInputBuffer *pInputBuffer, void **rData, long *rMaxNumberOfBytes);
  149. static void        InputBuffer_BytesAdded(tInputBuffer *pInputBuffer, long pNumberOfBytes);
  150.  
  151. // BinHexParser
  152.  
  153. static Boolean    BinHexParser_WriteDecodedData(tBinHexParser *pParser, void *pData, long pDataLength);
  154.  
  155. //----------------------------------------------
  156. // Global functions
  157. //----------------------------------------------
  158.  
  159. Boolean    UnpackBinHexFile(FSSpec *pSourceFile, FSSpec *pDestFile, FSSpec *rDestFile)
  160. {
  161.     OSErr                vErr;
  162.     short                vSourceFileRef;
  163.     tInputBuffer *        vInputBuffer;
  164.     tBinHexBuffer *        vBinHexBuffer;
  165.     FSSpec                vDestFile;
  166.     short                vDestFileRef;
  167.     tBinHexFileHeader    vHeader;
  168.     UInt16                vCalculatedChecksum;
  169.     UInt16                vFileChecksum;
  170.     FInfo                vFinderInfo;
  171.     Boolean                vHeaderIsValid;
  172.     
  173.     // Open the source file
  174.     
  175.     vErr = FSpOpenDF(pSourceFile, fsRdPerm, &vSourceFileRef);
  176.     if (vErr != noErr) return false;
  177.     
  178.     if (!InputBuffer_New(&vInputBuffer))
  179.         goto errorExit;
  180.     
  181.     if (!BinHexBuffer_New(&vBinHexBuffer))
  182.         goto errorExit2;
  183.     
  184.     // Search for the BinHex header
  185.     
  186.     vErr = InputBuffer_LoadFromFile(vInputBuffer, vSourceFileRef);
  187.     if (vErr != noErr) goto errorExit3;
  188.  
  189.     vErr = FindBinHexHeader(vInputBuffer);
  190.     if (vErr != noErr) goto errorExit3;
  191.     
  192.     // Read the header
  193.     
  194.     vErr = BinHexBuffer_LoadFromFile(vBinHexBuffer, vInputBuffer, vSourceFileRef);
  195.     if (vErr != noErr) goto errorExit3;
  196.     
  197.     vErr = GetBinHexFileHeader(vBinHexBuffer, &vHeaderIsValid, &vHeader);
  198.     if (vErr != noErr) goto errorExit3;
  199.     if (!vHeaderIsValid) goto errorExit3;
  200.     
  201.     // Create the destination FSSpec
  202.     
  203.     if (pDestFile != nil)
  204.         vDestFile = *pDestFile;
  205.     else {
  206.         vDestFile = *pSourceFile;
  207.         PLstrcpy(vDestFile.name, vHeader.FileName);
  208.         }
  209.     
  210.     // Create the destination file
  211.     
  212.     FSpDelete(&vDestFile);
  213.  
  214.     vErr = FSpCreate(&vDestFile, vHeader.FileCreator, vHeader.FileType, 0);
  215.     if (vErr != noErr) goto errorExit3;
  216.     
  217.     // Set the finder flags
  218.     
  219.     vErr = FSpGetFInfo(&vDestFile, &vFinderInfo);
  220.     if (vErr != noErr) goto errorExit4;
  221.     
  222.     vFinderInfo.fdFlags = vHeader.FinderFlags & ~(kIsInvisible | kHasBeenInited | kIsOnDesk);
  223.     
  224.     vErr = FSpSetFInfo(&vDestFile, &vFinderInfo);
  225.     if (vErr != noErr) goto errorExit4;
  226.     
  227.     // Open the data fork
  228.     
  229.     vErr = FSpOpenDF(&vDestFile, fsRdWrPerm, &vDestFileRef);
  230.     if (vErr != noErr) goto errorExit4;
  231.     
  232.     // Copy the data fork
  233.     
  234.     vCalculatedChecksum = 0;
  235.     if (!CopyBinHexToFile(vBinHexBuffer, vInputBuffer, vSourceFileRef, vDestFileRef, vHeader.DataLength, &vCalculatedChecksum))
  236.         goto errorExit5;
  237.     
  238.     AddByteToBinHexChecksum(0, &vCalculatedChecksum);
  239.     AddByteToBinHexChecksum(0, &vCalculatedChecksum);
  240.     
  241.     if (vBinHexBuffer->BytesAvailable < sizeof(UInt16)) {
  242.         vErr = BinHexBuffer_LoadFromFile(vBinHexBuffer, vInputBuffer, vSourceFileRef);
  243.         if (vErr != noErr) goto errorExit5;
  244.         }
  245.         
  246.     vErr = BinHexBuffer_ReadBytes(vBinHexBuffer, (UInt8 *)&vFileChecksum, sizeof(UInt16), nil);
  247.     if (vErr != noErr) goto errorExit5;
  248.  
  249. #if !cIgnoreChecksums    
  250.     if (vCalculatedChecksum != vFileChecksum)
  251.         goto errorExit5;
  252. #endif
  253.  
  254.     // Close the data fork
  255.     
  256.     FSClose(vDestFileRef);
  257.     
  258.     // Open the resource fork
  259.     
  260.     vErr = FSpOpenRF(&vDestFile, fsRdWrPerm, &vDestFileRef);
  261.     if (vErr != noErr) goto errorExit4;
  262.     
  263.     // Copy the resource fork
  264.     
  265.     vCalculatedChecksum = 0;
  266.     if (!CopyBinHexToFile(vBinHexBuffer, vInputBuffer, vSourceFileRef, vDestFileRef, vHeader.ResourceLength, &vCalculatedChecksum))
  267.         goto errorExit5;
  268.     
  269.     AddByteToBinHexChecksum(0, &vCalculatedChecksum);
  270.     AddByteToBinHexChecksum(0, &vCalculatedChecksum);
  271.     
  272.     if (vBinHexBuffer->BytesAvailable < sizeof(UInt16)) {
  273.         vErr = BinHexBuffer_LoadFromFile(vBinHexBuffer, vInputBuffer, vSourceFileRef);
  274.         if (vErr != noErr) goto errorExit5;
  275.         }
  276.         
  277.     vErr = BinHexBuffer_ReadBytes(vBinHexBuffer, (UInt8 *)&vFileChecksum, sizeof(UInt16), nil);
  278.     if (vErr != noErr) goto errorExit5;
  279.     
  280. #if !cIgnoreChecksums    
  281.     if (vCalculatedChecksum != vFileChecksum)
  282.         goto errorExit5;
  283. #endif
  284.     
  285.     // Close the resource fork
  286.     
  287.     FSClose(vDestFileRef);
  288.     
  289.     // Close the source file
  290.     
  291.     BinHexBuffer_Dispose(vBinHexBuffer);
  292.     InputBuffer_Dispose(vInputBuffer);
  293.     FSClose(vSourceFileRef);
  294.     
  295.     if (rDestFile != nil)
  296.         *rDestFile = vDestFile;
  297.     
  298.     return true;
  299.  
  300. errorExit5:
  301.     FSClose(vDestFileRef);
  302.     
  303. errorExit4:
  304.     FSpDelete(&vDestFile);
  305.  
  306. errorExit3:
  307.     BinHexBuffer_Dispose(vBinHexBuffer);
  308.         
  309. errorExit2:
  310.     InputBuffer_Dispose(vInputBuffer);
  311.     
  312. errorExit:
  313.     FSClose(vSourceFileRef);
  314.     
  315.     return false;
  316. }
  317.  
  318. Boolean    IsBinHexFile(FSSpec *pSourceFile, FSSpec *rDestFile)
  319. {
  320.     OSErr                vErr;
  321.     short                vSourceFileRef;
  322.     tInputBuffer *        vInputBuffer;
  323.     tBinHexBuffer *        vBinHexBuffer;
  324.     FSSpec                vDestFile;
  325.     tBinHexFileHeader    vHeader;
  326.     Boolean                vHeaderIsValid;
  327.     
  328.     // Open the source file
  329.     
  330.     vErr = FSpOpenDF(pSourceFile, fsRdPerm, &vSourceFileRef);
  331.     if (vErr != noErr) return false;
  332.     
  333.     if (!InputBuffer_New(&vInputBuffer))
  334.         goto errorExit;
  335.     
  336.     if (!BinHexBuffer_New(&vBinHexBuffer))
  337.         goto errorExit2;
  338.     
  339.     // Search for the BinHex header
  340.     
  341.     vErr = InputBuffer_LoadFromFile(vInputBuffer, vSourceFileRef);
  342.     if (vErr != noErr) goto errorExit3;
  343.  
  344.     vErr = FindBinHexHeader(vInputBuffer);
  345.     if (vErr != noErr) goto errorExit3;
  346.     
  347.     // Read the header
  348.     
  349.     vErr = BinHexBuffer_LoadFromFile(vBinHexBuffer, vInputBuffer, vSourceFileRef);
  350.     if (vErr != noErr) goto errorExit3;
  351.     
  352.     vErr = GetBinHexFileHeader(vBinHexBuffer, &vHeaderIsValid, &vHeader);
  353.     if (vErr != noErr) goto errorExit3;
  354.     if (!vHeaderIsValid) goto errorExit3;
  355.     
  356.     // Create the destination FSSpec
  357.     
  358.     vDestFile = *pSourceFile;
  359.     PLstrcpy(vDestFile.name, vHeader.FileName);
  360.     
  361.     // Close the source file
  362.     
  363.     BinHexBuffer_Dispose(vBinHexBuffer);
  364.     InputBuffer_Dispose(vInputBuffer);
  365.     FSClose(vSourceFileRef);
  366.     
  367.     // Return
  368.     
  369.     if (rDestFile != nil)
  370.         *rDestFile = vDestFile;
  371.     
  372.     return true;
  373.  
  374. errorExit3:
  375.     BinHexBuffer_Dispose(vBinHexBuffer);
  376.         
  377. errorExit2:
  378.     InputBuffer_Dispose(vInputBuffer);
  379.     
  380. errorExit:
  381.     FSClose(vSourceFileRef);
  382.     
  383.     return false;
  384. }
  385.  
  386. //----------------------------------------------
  387. // Local functions
  388. //----------------------------------------------
  389.  
  390. static OSErr    SkipReturn(tInputBuffer *pBuffer)
  391. {
  392.     OSErr    vErr;
  393.     
  394.     vErr = noErr;
  395.     
  396.     do {
  397.         UInt32    vIndex;
  398.         UInt8 *    vBufferData;
  399.         
  400.         if (pBuffer->BytesAvailable == 0)
  401.             vErr = eofErr;
  402.         
  403.         vBufferData = &pBuffer->Buffer[pBuffer->BufferOffset];
  404.         
  405.         for (vIndex = 0; vIndex < pBuffer->BytesAvailable; vIndex++) {
  406.             switch (*vBufferData) {
  407.                 case 0x09:
  408.                 case 0x0d:
  409.                 case 0x0a:
  410.                 case ' ':
  411.                     break;
  412.                 
  413.                 default:
  414.                     pBuffer->BufferOffset += vIndex;
  415.                     pBuffer->BytesAvailable -= vIndex;
  416.                     
  417.                     return noErr;
  418.                 } // switch
  419.             
  420.             vBufferData++;
  421.             } // for
  422.         
  423.         pBuffer->BufferOffset = pBuffer->BytesInBuffer;
  424.         pBuffer->BytesAvailable = 0;
  425.         
  426.         } while (vErr == noErr);
  427.     
  428.     return vErr;
  429. }
  430.  
  431. static OSErr    ReadFileToReturn(tInputBuffer *pBuffer, Boolean pKeepSpaces, void *pData, long pMaxLength, long *rActualLength)
  432. {
  433.     OSErr    vErr;
  434.     UInt8 *    vReadData;
  435.     long    vActualLength;
  436.     
  437.     vErr = noErr;
  438.     
  439.     vReadData = (UInt8 *)pData;
  440.     vActualLength = 0;
  441.     
  442.     do {
  443.         UInt32    vIndex;
  444.         UInt8 *    vBufferData;
  445.         
  446.         if (pBuffer->BytesAvailable == 0)
  447.             vErr = eofErr;
  448.         
  449.         vBufferData = &pBuffer->Buffer[pBuffer->BufferOffset];
  450.         
  451.         for (vIndex = 0; vIndex < pBuffer->BytesAvailable; vIndex++) {
  452.             switch (*vBufferData) {
  453.                 case 0x09:
  454.                 case 0x0d:
  455.                 case 0x0a:
  456.                 case ' ':
  457.                     
  458.                     if ((*vBufferData != ' ') || (!pKeepSpaces)) {
  459.                         pBuffer->BufferOffset += vIndex + 1;
  460.                         pBuffer->BytesAvailable -= vIndex + 1;
  461.                         
  462.                         if (rActualLength != nil)
  463.                             *rActualLength = vActualLength;
  464.                         
  465.                         return noErr;
  466.                         }
  467.                     
  468.                     // Fall through to keep space characters
  469.                 
  470.                 default:
  471.                     *vReadData = *vBufferData;
  472.                     vReadData++;
  473.                     vActualLength++;
  474.                     pMaxLength--;
  475.                     
  476.                     if (pMaxLength == 0) {
  477.                         pBuffer->BufferOffset += vIndex + 1;
  478.                         pBuffer->BytesAvailable -= vIndex + 1;
  479.                         
  480.                         if (rActualLength != nil)
  481.                             *rActualLength = vActualLength;
  482.                         
  483.                         return noErr;
  484.                         }
  485.                     
  486.                     break;
  487.                 } // switch
  488.             
  489.             vBufferData++;
  490.             } // for
  491.         
  492.         pBuffer->BufferOffset = pBuffer->BytesInBuffer;
  493.         pBuffer->BytesAvailable = 0;
  494.         
  495.         } while (vErr == noErr);
  496.     
  497.     return vErr;
  498. }
  499.  
  500. static OSErr    ReadOneCharacter(tInputBuffer *pBuffer, char *rCharacter)
  501. {
  502.     if (pBuffer->BytesAvailable == 0)
  503.         return eofErr;
  504.     
  505.     *rCharacter = pBuffer->Buffer[pBuffer->BufferOffset];
  506.     pBuffer->BufferOffset++;
  507.     pBuffer->BytesAvailable--;
  508.     
  509.     return noErr;
  510. }
  511.  
  512. #ifdef _MSC_VER
  513. char szBinHexFileHeader[40] = "(This file must be converted with BinHex";
  514. #endif
  515.  
  516. static OSErr    FindBinHexHeader(tInputBuffer *pBuffer)
  517. {
  518.     Str255        vText;
  519.     OSErr        vErr;
  520.     long        vActualLength;
  521.     Boolean        vFoundString1;
  522.     
  523.     vFoundString1 = false;
  524.     
  525.     do {
  526.         vErr = SkipReturn(pBuffer);
  527.         if (vErr != noErr) return vErr;
  528.         
  529.         vErr = ReadFileToReturn(pBuffer, true, &vText[1], sizeof(vText) - 1, &vActualLength);
  530.         if (vErr != noErr) return vErr;
  531.         
  532. #ifdef _MSC_VER
  533.         //    The MSVC runtimes don't include PLpos, so hopefully this is a
  534.         //    reasonable check to see if the file begins with this magic string.
  535.         if (vActualLength >= sizeof(szBinHexFileHeader) &&
  536.             memcmp(szBinHexFileHeader, &vText[1], sizeof(szBinHexFileHeader)) == 0) {
  537. #else
  538.         vText[0] = vActualLength;
  539.         
  540.         if (PLpos("\p(This file must be converted with BinHex", vText) == 1) {
  541. #endif
  542.             char    vChar;
  543.             
  544.             vErr = SkipReturn(pBuffer);
  545.             if (vErr != noErr) return vErr;
  546.             
  547.             vErr = ReadOneCharacter(pBuffer, &vChar);
  548.             if (vErr != noErr) return vErr;
  549.             
  550.             if (vChar == ':')
  551.                 return noErr;
  552.             }
  553.         
  554.         } while (vErr == noErr);
  555.     
  556.     return vErr;
  557. }
  558.  
  559. extern short gResFile;
  560.  
  561. static Boolean    BinHexBuffer_New(tBinHexBuffer **rBuffer)
  562. {
  563.     Handle    vConversionTable;
  564.     short    curResFile;
  565.  
  566.     if (gResFile == -1) return false;
  567.  
  568.     *rBuffer = (tBinHexBuffer *)NewPtrClear(sizeof(tBinHexBuffer));
  569.     if (MemError() != noErr) return false;
  570.     
  571.     curResFile = CurResFile();
  572.     UseResFile(gResFile);
  573.     vConversionTable = Get1Resource('HQXT', 128);
  574.     BlockMove(*vConversionTable, (**rBuffer).ConversionTable, 256);
  575.     UseResFile(curResFile);
  576.  
  577.     return true;
  578. }
  579.  
  580. static void        BinHexBuffer_Dispose(tBinHexBuffer *pBuffer)
  581. {
  582.     DisposePtr((Ptr)pBuffer);
  583. }
  584.  
  585. static OSErr    BinHexBuffer_LoadFromFile(tBinHexBuffer *pBuffer, tInputBuffer *pInputBuffer, short pFileRef)
  586. {
  587.     OSErr        vErr;
  588.     UInt32        vBytesUsed;
  589.     
  590.     // Load the source buffer
  591.     
  592.     if (pInputBuffer->BytesAvailable == 0) {
  593.         vErr = InputBuffer_LoadFromFile(pInputBuffer, pFileRef);
  594.         if (vErr != noErr) return vErr;
  595.         }
  596.     
  597.     if (!BinHexBuffer_Stuff(pBuffer, &pInputBuffer->Buffer[pInputBuffer->BufferOffset], pInputBuffer->BytesAvailable, &vBytesUsed))
  598.         return paramErr;
  599.     
  600.     pInputBuffer->BufferOffset += vBytesUsed;
  601.     pInputBuffer->BytesAvailable -= vBytesUsed;
  602.     
  603.     return noErr;
  604. }
  605.  
  606. static Boolean    BinHexBuffer_Stuff(tBinHexBuffer *pBuffer, UInt8 *pData, UInt32 pNumberOfBytes, UInt32 *rBytesStuffed)
  607. {
  608.     UInt8 *        vNextSourceByte;
  609.     int            vHoldingPhase;
  610.     int            vHoldingByte;
  611.     UInt8 *        vNextDestByte;
  612.     int            vPreviousByte;
  613.     Boolean        vRepeatFlagFound;
  614.     UInt32        vBytesAvailable;
  615.     
  616.     if (pBuffer->BytesInBuffer == pBuffer->BufferOffset) {
  617.         pBuffer->BytesInBuffer = 0;
  618.         pBuffer->BufferOffset = 0;
  619.         }
  620.     
  621.     if (pBuffer->TerminatorFound)
  622.         return pNumberOfBytes;
  623.     
  624.     // Restore our local variables
  625.     
  626.     vNextSourceByte = pData;
  627.     vNextDestByte = &pBuffer->Buffer[pBuffer->BufferOffset];
  628.     
  629.     vHoldingPhase = pBuffer->HoldingPhase;
  630.     vHoldingByte = pBuffer->HoldingByte;
  631.     vPreviousByte = pBuffer->PreviousByte;
  632.     vRepeatFlagFound = pBuffer->RepeatFlagFound;
  633.     
  634.     vBytesAvailable = pNumberOfBytes;
  635.     
  636.     while ((vBytesAvailable > 0)
  637.      && (!pBuffer->TerminatorFound)
  638.      && (pBuffer->BytesInBuffer < cBuffer_Size - 256)) {
  639.         int            vByte6;
  640.         int            vByte;
  641.         
  642.         vByte6 = pBuffer->ConversionTable[*vNextSourceByte++];
  643.         vBytesAvailable--;
  644.         
  645.         if (vByte6 < 64) {
  646.             switch (vHoldingPhase) {
  647.                 case 0:
  648.                     vHoldingByte = vByte6 << 2;
  649.                     vHoldingPhase = 1;
  650.                     
  651.                     continue;
  652.                 
  653.                 case 1:
  654.                     vByte = vHoldingByte | (vByte6 >> 4);
  655.                     
  656.                     vHoldingByte = vByte6 << 4;
  657.                     vHoldingPhase = 2;
  658.                     break;
  659.                 
  660.                 case 2:
  661.                     vByte = vHoldingByte | (vByte6 >> 2);
  662.                     
  663.                     vHoldingByte = vByte6 << 6;
  664.                     vHoldingPhase = 3;
  665.                     break;
  666.                 
  667.                 case 3:
  668.                     vByte = vHoldingByte | vByte6;
  669.                     
  670.                     vHoldingPhase = 0;
  671.                     break;
  672.                 } // switch
  673.             
  674.             vByte = vByte & 0x0ff;
  675.             
  676.             if (vRepeatFlagFound) {
  677.                 vRepeatFlagFound = false;
  678.                 
  679.                 if (vByte == 0)
  680.                     vByte = 0x90;
  681.                 else {
  682.                     while (--vByte) {
  683.                         *vNextDestByte = vPreviousByte;
  684.                         vNextDestByte++;
  685.                         pBuffer->BytesInBuffer++;
  686.                         } // for
  687.                     
  688.                     continue;
  689.                     }
  690.                 }
  691.             else {
  692.                 if (vByte == 0x90) {
  693.                     vRepeatFlagFound = true;
  694.                     continue;
  695.                     }
  696.                 }
  697.             
  698.             *vNextDestByte++ = vByte;
  699.             pBuffer->BytesInBuffer++;
  700.             
  701.             vPreviousByte = vByte;
  702.             }
  703.         else {
  704.             switch (vByte6) {
  705.                 case 0xfd: // whitespace (just ignore)
  706.                     break;
  707.                 
  708.                 case 0xfe:
  709.                     pBuffer->TerminatorFound = true;
  710.                     break;
  711.                 
  712.                 case 0xff:
  713.                     return false;
  714.                 } // switch
  715.             }
  716.  
  717.         } // while
  718.     
  719.     pBuffer->HoldingPhase = vHoldingPhase;
  720.     pBuffer->HoldingByte = vHoldingByte;
  721.     pBuffer->PreviousByte = vPreviousByte;
  722.     pBuffer->RepeatFlagFound = vRepeatFlagFound;
  723.     
  724.     pBuffer->BytesAvailable = pBuffer->BytesInBuffer - pBuffer->BufferOffset;
  725.     
  726.     *rBytesStuffed = pNumberOfBytes - vBytesAvailable;
  727.     
  728.     return true;
  729. }
  730.  
  731. static OSErr    BinHexBuffer_ReadByte(tBinHexBuffer *pBuffer, UInt8 *rByte, UInt16 *rChecksum)
  732. {
  733.     if (pBuffer->BytesAvailable == 0)
  734.         return eofErr;
  735.     
  736.     *rByte = pBuffer->Buffer[pBuffer->BufferOffset];
  737.     pBuffer->BufferOffset++;
  738.     pBuffer->BytesAvailable--;
  739.     
  740.     if (rChecksum != nil)
  741.         AddByteToBinHexChecksum(*rByte, rChecksum);
  742.     
  743.     return noErr;
  744. }
  745.  
  746. static OSErr    BinHexBuffer_ReadBytes(tBinHexBuffer *pBuffer, UInt8 *pReadBuffer, UInt32 pNumberOfBytes, UInt16 *rChecksum)
  747. {
  748.     if (pNumberOfBytes > pBuffer->BytesAvailable)
  749.         return eofErr;
  750.     
  751.     if (pNumberOfBytes == 0)
  752.         return eofErr;
  753.     
  754.     BlockMove(&pBuffer->Buffer[pBuffer->BufferOffset], pReadBuffer, pNumberOfBytes);
  755.     
  756.     if (rChecksum != nil)
  757.         AddBytesToBinHexChecksum(pReadBuffer, pNumberOfBytes, rChecksum);
  758.     
  759.     pBuffer->BufferOffset += pNumberOfBytes;
  760.     pBuffer->BytesAvailable -= pNumberOfBytes;
  761.     
  762.     return noErr;
  763. }
  764.  
  765. static void        AddByteToBinHexChecksum(UInt8 pValue, UInt16 *rChecksum)
  766. {
  767.     SInt32    vChecksum;
  768.     int        vIndex;
  769.     SInt32    vSeedValue;
  770.     
  771. #if cIgnoreChecksums    
  772.     return;
  773. #endif
  774.  
  775.     vChecksum = ((UInt32)*rChecksum << 16) | ((UInt32)pValue << 8);
  776.     vSeedValue = 0x10210000;
  777.     
  778.     vIndex = 8;
  779.     do {
  780.         if (vChecksum < 0)
  781.             vChecksum = (vChecksum << 1) ^ vSeedValue;
  782.         else
  783.             vChecksum = vChecksum << 1;
  784.         } while (--vIndex > 0);
  785.     
  786.     *rChecksum = vChecksum >> 16;
  787. }
  788.  
  789. static void        AddBytesToBinHexChecksum(UInt8 *pValues, UInt32 pNumberOfBytes, UInt16 *rChecksum)
  790. {
  791. #if cIgnoreChecksums    
  792.     return;
  793. #endif
  794.  
  795.     while (pNumberOfBytes > 0) {
  796.         AddByteToBinHexChecksum(*pValues, rChecksum);
  797.         pValues++;
  798.         
  799.         pNumberOfBytes--;
  800.         } // while
  801. }
  802.  
  803. static OSErr    GetBinHexFileHeader(tBinHexBuffer *pBuffer, Boolean *rHeaderIsValid, tBinHexFileHeader *rHeader)
  804. {
  805.     UInt16    vCalculatedChecksum;
  806.     UInt8    vTempByte;
  807.     OSErr    vErr;
  808.     UInt16    vActualChecksum;
  809.     
  810.     vCalculatedChecksum = 0;
  811.     
  812.     *rHeaderIsValid = false;
  813.  
  814.     vErr = BinHexBuffer_ReadByte(pBuffer, &rHeader->FileName[0], &vCalculatedChecksum);
  815.     if (vErr != noErr) return vErr;
  816.     
  817.     vErr = BinHexBuffer_ReadBytes(pBuffer, &rHeader->FileName[1], rHeader->FileName[0], &vCalculatedChecksum);
  818.     if (vErr != noErr) return vErr;
  819.     
  820.     vErr = BinHexBuffer_ReadByte(pBuffer, &vTempByte, &vCalculatedChecksum);
  821.     if (vErr != noErr) return vErr;
  822.     
  823.     if (vTempByte != 0) return vErr;
  824.     
  825.     vErr = BinHexBuffer_ReadBytes(pBuffer, (UInt8 *)&rHeader->FileType, sizeof(tBinHexFileHeader) - sizeof(Str63), &vCalculatedChecksum);
  826.     if (vErr != noErr) return vErr;
  827.     
  828.     vErr = BinHexBuffer_ReadBytes(pBuffer, (UInt8 *)&vActualChecksum, sizeof(short), nil);
  829.     if (vErr != noErr) return vErr;
  830.     
  831.     AddByteToBinHexChecksum(0, &vCalculatedChecksum);
  832.     AddByteToBinHexChecksum(0, &vCalculatedChecksum);
  833.     
  834. #if cIgnoreChecksums    
  835.     *rHeaderIsValid = true;
  836. #else
  837.     *rHeaderIsValid = (vActualChecksum == vCalculatedChecksum);
  838. #endif
  839.     return noErr;
  840. }
  841.  
  842. static Boolean    CopyBinHexToFile(tBinHexBuffer *pBuffer, tInputBuffer *pInputBuffer, short pSourceFileRef, short pDestFileRef, UInt32 pNumberOfBytes, UInt16 *rChecksum)
  843. {
  844.     OSErr    vErr;
  845.     
  846.     while (pNumberOfBytes > 0) {
  847.         long    vNumberOfBytes;
  848.         
  849.         if (pBuffer->BytesAvailable == 0) {
  850.             vErr = BinHexBuffer_LoadFromFile(pBuffer, pInputBuffer, pSourceFileRef);
  851.             if (vErr != noErr) return false;;
  852.             } // if
  853.         
  854.         if (pNumberOfBytes > pBuffer->BytesAvailable)
  855.             vNumberOfBytes = pBuffer->BytesAvailable;
  856.         else
  857.             vNumberOfBytes = pNumberOfBytes;
  858.             
  859.         vErr = FSWrite(pDestFileRef, &vNumberOfBytes, &pBuffer->Buffer[pBuffer->BufferOffset]);
  860.         if (vErr != noErr) return false;;
  861.         
  862.         if (rChecksum != nil)
  863.             AddBytesToBinHexChecksum(&pBuffer->Buffer[pBuffer->BufferOffset], vNumberOfBytes, rChecksum);
  864.         
  865.         pNumberOfBytes -= vNumberOfBytes;
  866.         
  867.         pBuffer->BufferOffset += vNumberOfBytes;
  868.         pBuffer->BytesAvailable -= vNumberOfBytes;
  869.         } // while
  870.     
  871.     return true;
  872. }
  873.  
  874. //----------------------------------------------
  875. // InputBuffer
  876. //----------------------------------------------
  877.  
  878. static Boolean    InputBuffer_New(tInputBuffer **rBuffer)
  879. {
  880.     *rBuffer = (tInputBuffer *)NewPtrClear(sizeof(tInputBuffer));
  881.     if (MemError() != noErr) return false;
  882.     
  883.     return true;
  884. }
  885.  
  886. static void        InputBuffer_Dispose(tInputBuffer *pBuffer)
  887. {
  888.     DisposePtr((Ptr)pBuffer);
  889. }
  890.  
  891. static OSErr    InputBuffer_LoadFromFile(tInputBuffer *pBuffer, short pFileRef)
  892. {
  893.     OSErr    vErr;
  894.     void *    vBufferData;
  895.     long    vMaximumBytes;
  896.     long    vFileSize;
  897.     long    vNumberOfBytes;
  898.     
  899.     // Get the buffer pointer and maximum size
  900.     
  901.     InputBuffer_GetPointer(pBuffer, &vBufferData, &vMaximumBytes);
  902.     
  903.     // Calculate the number of bytes to read
  904.     
  905.     GetEOF(pFileRef, &vFileSize);
  906.     
  907.     vNumberOfBytes = vFileSize - pBuffer->FileOffset;
  908.     if (vNumberOfBytes == 0)
  909.         return eofErr;
  910.  
  911.     if (vNumberOfBytes > vMaximumBytes)
  912.         vNumberOfBytes = vMaximumBytes;
  913.     
  914.     // Read the data
  915.     
  916.     vErr = SetFPos(pFileRef, fsFromStart, pBuffer->FileOffset);
  917.     if (vErr != noErr) return vErr;
  918.     
  919.     vErr = FSRead(pFileRef, &vNumberOfBytes, vBufferData);
  920.     if (vErr != noErr) return vErr;
  921.     
  922.     // Tell the buffer about the new data
  923.     
  924.     InputBuffer_BytesAdded(pBuffer, vNumberOfBytes);
  925.     
  926.     return noErr;
  927. }
  928.  
  929. #ifdef MAC_IE_ONLY
  930. static long     InputBuffer_Stuff(tInputBuffer *pInputBuffer, void *pData, long pNumberOfBytes)
  931. {
  932.     void *    vBufferData;
  933.     long    vNumberOfBytes;
  934.     
  935.     InputBuffer_GetPointer(pInputBuffer, &vBufferData, &vNumberOfBytes);
  936.     
  937.     if (vNumberOfBytes > pNumberOfBytes)
  938.         vNumberOfBytes = pNumberOfBytes;
  939.     
  940.     BlockMove(pData, vBufferData, vNumberOfBytes);
  941.     
  942.     InputBuffer_BytesAdded(pInputBuffer, vNumberOfBytes);
  943.     
  944.     return vNumberOfBytes;
  945. }
  946.  
  947. static void        InputBuffer_DeleteOldData(tInputBuffer *pInputBuffer)
  948. {
  949.     void *    vSourceData;
  950.     long    vNumberOfBytes;
  951.     
  952.     vNumberOfBytes = pInputBuffer->BytesInBuffer - pInputBuffer->BufferOffset;
  953.     
  954.     if (vNumberOfBytes == 0) {
  955.         pInputBuffer->BufferOffset = 0;
  956.         pInputBuffer->BytesInBuffer = 0;
  957.         return;
  958.         }
  959.     
  960.     vSourceData = &pInputBuffer->Buffer[pInputBuffer->BufferOffset];
  961.     
  962.     BlockMove(vSourceData, &pInputBuffer->Buffer[0], vNumberOfBytes);
  963.     
  964.     pInputBuffer->BufferOffset = 0;
  965.     pInputBuffer->BytesInBuffer = vNumberOfBytes;
  966. }
  967. #endif
  968.  
  969. static void        InputBuffer_GetPointer(tInputBuffer *pInputBuffer, void **rData, long *rMaxNumberOfBytes)
  970. {
  971.     if (pInputBuffer->BufferOffset == pInputBuffer->BytesInBuffer) {
  972.         pInputBuffer->BufferOffset = 0;
  973.         pInputBuffer->BytesInBuffer = 0;
  974.         }
  975.     
  976.     *rData = &pInputBuffer->Buffer[pInputBuffer->BytesInBuffer];
  977.     *rMaxNumberOfBytes = cBuffer_Size - pInputBuffer->BytesInBuffer;
  978. }
  979.  
  980. static void        InputBuffer_BytesAdded(tInputBuffer *pInputBuffer, long pNumberOfBytes)
  981. {
  982.     pInputBuffer->BytesInBuffer += pNumberOfBytes;
  983.     pInputBuffer->BytesAvailable += pNumberOfBytes;
  984.     pInputBuffer->FileOffset += pNumberOfBytes;
  985. }
  986.  
  987. #ifdef MAC_IE_ONLY
  988. //----------------------------------------------
  989. // BinHex Parser
  990. //----------------------------------------------
  991.  
  992. Boolean    BinHexParser_New(tBinHexClientData *pClientData, tBinHexParserCallbacks *pCallbacks, tBinHexParser **rParser)
  993. {
  994.     tBinHexParser *    vParser;
  995.     
  996.     vParser = (tBinHexParser *)NewPtr(sizeof(struct tBinHexParser));
  997.     if (MemError() != noErr)
  998.         return false;
  999.     
  1000.     vParser->fClientData = pClientData;
  1001.     vParser->fCallbacks = pCallbacks;
  1002.     
  1003.     if (!InputBuffer_New(&vParser->fInputBuffer))
  1004.         goto error1;
  1005.     
  1006.     if (!BinHexBuffer_New(&vParser->fBinHexBuffer))
  1007.         goto error2;
  1008.         
  1009.     vParser->fParserState = cValidating_ParserState;
  1010.     vParser->fByteCount = 0;
  1011.     
  1012.     *rParser = vParser;
  1013.     
  1014.     return true;
  1015.  
  1016. //-------------------
  1017. error2:
  1018.     InputBuffer_Dispose(vParser->fInputBuffer);
  1019.     
  1020. error1:
  1021.     DisposePtr((Ptr)vParser);
  1022.     return false;
  1023. }
  1024.  
  1025. void    BinHexParser_Dispose(tBinHexParser *pParser)
  1026. {
  1027.     BinHexParser_Flush(pParser);
  1028.     
  1029.     BinHexBuffer_Dispose(pParser->fBinHexBuffer);
  1030.     
  1031.     InputBuffer_Dispose(pParser->fInputBuffer);
  1032.     
  1033.     DisposePtr((Ptr)pParser);
  1034. }
  1035.  
  1036. Boolean    BinHexParser_Flush(tBinHexParser *pParser)
  1037. {
  1038.     if (pParser->fParserState == cValidating_ParserState) {
  1039.         
  1040.         pParser->fParserState = cPassThrough_ParserState;
  1041.         
  1042.         if (pParser->fInputBuffer->BytesInBuffer > 0)
  1043.             if (!BinHexParser_WriteData(pParser, pParser->fInputBuffer->Buffer, pParser->fInputBuffer->BytesInBuffer))
  1044.                 return false;
  1045.         } // if
  1046.     
  1047.     return true;
  1048. }
  1049.  
  1050. void    BinHexParser_Kill(tBinHexParser *pParser)
  1051. {
  1052.     pParser->fParserState = cPassThrough_ParserState;
  1053. }
  1054.  
  1055. Boolean    BinHexParser_WriteData(tBinHexParser *pParser, void *pData, long pDataLength)
  1056. {
  1057.     while (pDataLength > 0) {
  1058.         
  1059.         switch (pParser->fParserState) {
  1060.             
  1061.             case cValidating_ParserState: {
  1062.                 UInt32    vBytesStuffed;
  1063.                 OSErr    vErr;
  1064.                 
  1065.                 // Reset the input buffer so that we're searching from the beginning each time (the search code isn't very bright)
  1066.                 
  1067.                 pParser->fInputBuffer->BufferOffset = 0;
  1068.                 pParser->fInputBuffer->BytesAvailable = pParser->fInputBuffer->BytesInBuffer;
  1069.                 
  1070.                 // Stuff as much of the new data into the buffer as will fit
  1071.                 
  1072.                 vBytesStuffed = InputBuffer_Stuff(pParser->fInputBuffer, pData, pDataLength);
  1073.                 pData = (UInt8 *)pData + vBytesStuffed;
  1074.                 pDataLength -= vBytesStuffed;
  1075.                 
  1076.                 // See if there's a header in there somewhere
  1077.                 
  1078.                 vErr = FindBinHexHeader(pParser->fInputBuffer);
  1079.                 if (vErr == noErr) {
  1080.                     // Found the header - start parsing data
  1081.                     
  1082.                     InputBuffer_DeleteOldData(pParser->fInputBuffer);
  1083.                     
  1084.                     pParser->fParserState = cHeaderNameLength_ParserState;
  1085.                     pParser->fByteCount = 0;
  1086.                     
  1087.                     // Call ourselves recursively to process the remains of the buffer
  1088.                     
  1089.                     if ((pParser->fInputBuffer->BytesAvailable > 0)
  1090.                       && !BinHexParser_WriteData(pParser, pParser->fInputBuffer->Buffer, pParser->fInputBuffer->BytesAvailable))
  1091.                         return false;
  1092.                     
  1093.                     break;
  1094.                     } // if
  1095.                 
  1096.                 if (pParser->fInputBuffer->BytesInBuffer == cBuffer_Size) {
  1097.                     
  1098.                     // The buffer's full and we still haven't found the data - switch to pass-through mode
  1099.                     
  1100.                     if (!BinHexParser_Flush(pParser))
  1101.                         return false;
  1102.                     
  1103.                     } // if
  1104.                 
  1105.                 break;
  1106.                 }
  1107.             
  1108.             case cHeaderNameLength_ParserState:
  1109.             case cHeaderName_ParserState:
  1110.             case cHeaderNamePad_ParserState:
  1111.             case cHeader_ParserState:
  1112.             case cHeaderChecksum_ParserState:
  1113.             case cDataFork_ParserState:
  1114.             case cDataForkChecksum_ParserState:
  1115.             case cResourceFork_ParserState:
  1116.             case cResourceForkChecksum_ParserState: {
  1117.                 long    vBytesStuffed;
  1118.                 
  1119.                 if (!BinHexBuffer_Stuff(pParser->fBinHexBuffer, pData, pDataLength, &vBytesStuffed))
  1120.                     return false;
  1121.                 
  1122.                 if ((pParser->fBinHexBuffer->BytesAvailable > 0)
  1123.                   && !BinHexParser_WriteDecodedData(pParser, &pParser->fBinHexBuffer->Buffer[pParser->fBinHexBuffer->BufferOffset], pParser->fBinHexBuffer->BytesAvailable))
  1124.                     return false;
  1125.                 
  1126.                 pParser->fBinHexBuffer->BufferOffset = pParser->fBinHexBuffer->BytesInBuffer;
  1127.                 pParser->fBinHexBuffer->BytesAvailable = 0;
  1128.                 
  1129.                 pData = (UInt8 *)pData + vBytesStuffed;
  1130.                 pDataLength -= vBytesStuffed;
  1131.                 
  1132.                 break;
  1133.                 }
  1134.             
  1135.             case cPassThrough_ParserState:
  1136.                 if (!pParser->fCallbacks->WriteDF(pParser->fClientData, pData, pDataLength))
  1137.                     return false;
  1138.                 
  1139.                 pDataLength = 0;
  1140.                 break;
  1141.                 
  1142.             case cDiscard_ParserState:
  1143.                 pDataLength = 0;
  1144.                 break;
  1145.             
  1146.             default:
  1147.                 DebugStr("\pBinHexParser_WriteData: Illegal switch selector");
  1148.                 break;
  1149.             
  1150.             } // switch
  1151.         
  1152.         } // while
  1153.     
  1154.     return true;
  1155. }
  1156.  
  1157. Boolean    BinHexParser_IsBinHex(tBinHexParser *pParser)
  1158. {
  1159.     return ((pParser->fParserState != cValidating_ParserState) && (pParser->fParserState != cPassThrough_ParserState));
  1160. }
  1161.  
  1162. static Boolean    BinHexParser_WriteDecodedData(tBinHexParser *pParser, void *pData, long pDataLength)
  1163. {
  1164.     while (pDataLength > 0) {
  1165.         
  1166.         switch (pParser->fParserState) {
  1167.             
  1168.             case cHeaderNameLength_ParserState:
  1169.             
  1170.                 pParser->fCalculatedChecksum = 0;
  1171.                 
  1172.                 pParser->fByteCount = *(UInt8 *)pData;
  1173.                 AddByteToBinHexChecksum(pParser->fByteCount, &pParser->fCalculatedChecksum);
  1174.                 
  1175.                 pData = (UInt8 *)pData + 1;
  1176.                 pDataLength -= 1;
  1177.                 
  1178.                 pParser->fHeader.FileName[0] = 0; // The length byte will get incremented as the name is read in
  1179.                 
  1180.                 pParser->fParserState = cHeaderName_ParserState;
  1181.                 break;
  1182.             
  1183.             case cHeaderName_ParserState: {
  1184.                 long    vNumberOfBytes;
  1185.                 
  1186.                 vNumberOfBytes = pParser->fByteCount;
  1187.                 if (vNumberOfBytes > pDataLength)
  1188.                     vNumberOfBytes = pDataLength;
  1189.                 
  1190.                 BlockMove(pData, &pParser->fHeader.FileName[pParser->fHeader.FileName[0] + 1], vNumberOfBytes);
  1191.                 AddBytesToBinHexChecksum(pData, vNumberOfBytes, &pParser->fCalculatedChecksum);
  1192.                 
  1193.                 pParser->fHeader.FileName[0] += vNumberOfBytes;
  1194.                 
  1195.                 pData = (UInt8 *)pData + vNumberOfBytes;
  1196.                 pDataLength -= vNumberOfBytes;
  1197.                 
  1198.                 pParser->fByteCount -= vNumberOfBytes;
  1199.                 if (pParser->fByteCount == 0) {
  1200.                     pParser->fParserState = cHeaderNamePad_ParserState;
  1201.                     } // if
  1202.                 
  1203.                 break;
  1204.                 }
  1205.             
  1206.             case cHeaderNamePad_ParserState:
  1207.                 if (*(UInt8 *)pData != 0)
  1208.                     return false;
  1209.                 
  1210.                 AddByteToBinHexChecksum(*(UInt8 *)pData, &pParser->fCalculatedChecksum);
  1211.                 
  1212.                 pData = (UInt8 *)pData + 1;
  1213.                 pDataLength -= 1;
  1214.                 
  1215.                 pParser->fParserState = cHeader_ParserState;
  1216.                 pParser->fByteCount = 0;
  1217.                 break;
  1218.                 
  1219.             case cHeader_ParserState: {
  1220.                 long    vNumberOfBytes;
  1221.                 
  1222.                 vNumberOfBytes = (sizeof(tBinHexFileHeader) - sizeof(Str63)) - pParser->fByteCount;
  1223.                 if (vNumberOfBytes > pDataLength)
  1224.                     vNumberOfBytes = pDataLength;
  1225.                 
  1226.                 BlockMove(pData, (UInt8 *)&pParser->fHeader.FileType + pParser->fByteCount, vNumberOfBytes);
  1227.                 AddBytesToBinHexChecksum(pData, vNumberOfBytes, &pParser->fCalculatedChecksum);
  1228.                 
  1229.                 pParser->fByteCount += vNumberOfBytes;
  1230.                 
  1231.                 pData = (UInt8 *)pData + vNumberOfBytes;
  1232.                 pDataLength -= vNumberOfBytes;
  1233.                 
  1234.                 if (pParser->fByteCount == (sizeof(tBinHexFileHeader) - sizeof(Str63))) {
  1235.                     pParser->fParserState = cHeaderChecksum_ParserState;
  1236.                     pParser->fByteCount = sizeof(UInt16);
  1237.                     }
  1238.                 
  1239.                 break;
  1240.                 }
  1241.             
  1242.             case cHeaderChecksum_ParserState:
  1243.             case cDataForkChecksum_ParserState:
  1244.             case cResourceForkChecksum_ParserState: {
  1245.                 tBinHexFileInfo    vFileInfo;
  1246.                 
  1247.                 // Collect the two bytes for the checksum
  1248.                 
  1249.                 if (pDataLength > 1) {
  1250.                     if (pParser->fByteCount == 1) {
  1251.                         *((UInt8 *)&pParser->fActualChecksum + 1) = *(UInt8 *)pData;
  1252.                         
  1253.                         pData = (UInt8 *)pData + 1;
  1254.                         pDataLength -= 1;
  1255.                         }
  1256.                     else {
  1257.                         pParser->fActualChecksum = *(UInt16 *)pData;
  1258.                         
  1259.                         pData = (UInt8 *)pData + sizeof(UInt16);
  1260.                         pDataLength -= sizeof(UInt16);
  1261.                         }
  1262.                     }
  1263.                 else {
  1264.                     *((UInt8 *)&pParser->fActualChecksum) = *(UInt8 *)pData;
  1265.                     
  1266.                     pData = (UInt8 *)pData + 1;
  1267.                     pDataLength -= 1;
  1268.                     
  1269.                     pParser->fByteCount -= 1;
  1270.                     break;
  1271.                     }
  1272.                 
  1273.                 // Include two zero bytes in the calculated checksum
  1274.                 
  1275.                 AddByteToBinHexChecksum(0, &pParser->fCalculatedChecksum);
  1276.                 AddByteToBinHexChecksum(0, &pParser->fCalculatedChecksum);
  1277.                 
  1278.                 // Completed the header - verify the checksum
  1279.                 
  1280.                 if (pParser->fActualChecksum != pParser->fCalculatedChecksum)
  1281.                     return false;
  1282.                 
  1283.                 switch (pParser->fParserState) {
  1284.                     case cHeaderChecksum_ParserState: {
  1285.                         // Send the header to the client
  1286.                         
  1287.                         BlockMove(pParser->fHeader.FileName, vFileInfo.fName, sizeof(Str63));
  1288.                         vFileInfo.fFileType = pParser->fHeader.FileType;
  1289.                         vFileInfo.fFileCreator = pParser->fHeader.FileCreator;
  1290.                         vFileInfo.fFinderFlags = pParser->fHeader.FinderFlags;
  1291.                         
  1292.                         if (!pParser->fCallbacks->SetFileInfo(pParser->fClientData, &vFileInfo))
  1293.                             return false;
  1294.                         
  1295.                         // Start parsing the data fork
  1296.                         
  1297.                         pParser->fParserState = cDataFork_ParserState;
  1298.                         pParser->fByteCount = pParser->fHeader.DataLength;
  1299.                         pParser->fCalculatedChecksum = 0;
  1300.                         
  1301.                         break;
  1302.                         }
  1303.                         
  1304.                     case cDataForkChecksum_ParserState:
  1305.                         pParser->fParserState = cResourceFork_ParserState;
  1306.                         pParser->fByteCount = pParser->fHeader.ResourceLength;
  1307.                         pParser->fCalculatedChecksum = 0;
  1308.                         break;
  1309.                         
  1310.                     case cResourceForkChecksum_ParserState:
  1311.                         pParser->fParserState = cDiscard_ParserState;
  1312.                         pParser->fByteCount = 0;
  1313.                         break;
  1314.                     } // switch
  1315.                 
  1316.                 break;
  1317.                 }
  1318.             
  1319.             case cDataFork_ParserState:
  1320.                 
  1321.                 if (pDataLength >= pParser->fByteCount) {
  1322.                     AddBytesToBinHexChecksum(pData, pParser->fByteCount, &pParser->fCalculatedChecksum);
  1323.                     
  1324.                     if (!pParser->fCallbacks->WriteDF(pParser->fClientData, pData, pParser->fByteCount))
  1325.                         return false;
  1326.                     
  1327.                     pData = (void *)((UInt8 *)pData + pParser->fByteCount);
  1328.                     pDataLength -= pParser->fByteCount;
  1329.                     
  1330.                     pParser->fParserState = cDataForkChecksum_ParserState;
  1331.                     pParser->fByteCount = sizeof(UInt16);
  1332.                     }
  1333.                 else {
  1334.                     AddBytesToBinHexChecksum(pData, pDataLength, &pParser->fCalculatedChecksum);
  1335.                     
  1336.                     if (!pParser->fCallbacks->WriteDF(pParser->fClientData, pData, pDataLength))
  1337.                         return false;
  1338.                     
  1339.                     pParser->fByteCount -= pDataLength;
  1340.                     pDataLength = 0;
  1341.                     }
  1342.                 
  1343.                 break;
  1344.             
  1345.             case cResourceFork_ParserState:
  1346.             
  1347.                 if (pDataLength >= pParser->fByteCount) {
  1348.                     AddBytesToBinHexChecksum(pData, pParser->fByteCount, &pParser->fCalculatedChecksum);
  1349.                     
  1350.                     if (!pParser->fCallbacks->WriteRF(pParser->fClientData, pData, pParser->fByteCount))
  1351.                         return false;
  1352.                     
  1353.                     pData = (void *)((UInt8 *)pData + pParser->fByteCount);
  1354.                     pDataLength -= pParser->fByteCount;
  1355.                     
  1356.                     pParser->fParserState = cResourceForkChecksum_ParserState;
  1357.                     pParser->fByteCount = sizeof(UInt16);
  1358.                     }
  1359.                 else {
  1360.                     AddBytesToBinHexChecksum(pData, pDataLength, &pParser->fCalculatedChecksum);
  1361.                     
  1362.                     if (!pParser->fCallbacks->WriteRF(pParser->fClientData, pData, pDataLength))
  1363.                         return false;
  1364.                     
  1365.                     pParser->fByteCount -= pDataLength;
  1366.                     pDataLength = 0;
  1367.                     }
  1368.                 
  1369.                 break;
  1370.             
  1371.             case cPassThrough_ParserState:
  1372.                 if (!pParser->fCallbacks->WriteDF(pParser->fClientData, pData, pDataLength))
  1373.                     return false;
  1374.                 
  1375.                 pDataLength = 0;
  1376.                 break;
  1377.                 
  1378.             case cDiscard_ParserState:
  1379.                 pDataLength = 0;
  1380.                 break;
  1381.             
  1382.             default:
  1383.                 DebugStr("\pBinHexParser_WriteData: Illegal switch selector");
  1384.                 break;
  1385.             
  1386.             } // switch
  1387.         
  1388.         } // while
  1389.     
  1390.     return true;
  1391. }
  1392. #endif
  1393.